#pragma once

#include <iostream>
#include <TFile.h>
#include <TTree.h>
#include <vector>
#include <TH1I.h>
#include <TF1.h>
#include <TCanvas.h>
#include <TGraphErrors.h>
#include <iomanip>
#include "TROOT.h"
#include <TStyle.h>
#include <TLatex.h>

#include <string>
#include <vector>
#include <filesystem>
#include <algorithm>
#include <numeric>

#include <eigen3/Eigen/Dense>
#include <cmath>
#include <fstream>
#include "constant.hh"
#include "position_data.hh"
#include "MyTracker.hh"

using namespace std;

class fit_pro
{
public:
  fit_pro(string input_file_name, string align_filename, string range_filename, int layer_num, float rmse_precision, bool idx_discontinuous, int idx_disc, double sigma, double LSB, string save_path);
  ~fit_pro();

  bool is_file_get = false;

  int det_layer_used;
  int layer_len;
  int idx_disc;
  bool idx_discontinuous;
  float rmse_precision;
  float t_target_z;
  double sigma;
  double LSB;
  string save_path;

  int setlayer = 0;
  int setlayer_used = 6;

private:
  // 读取root文件
  int total_entried_num = 0;

  TFile *hit_data_file;
  TTree *hit_data_tree;
  int trigger_id;
  position_data detector_data[cMAX_DET_LAYER];
  TBranch *b_triggera_id;
  TBranch *b_total_layer_num;
  TBranch *b_detector_data[cMAX_DET_LAYER];

  /* params */
  vector<float> alignment;
  vector<float> x_alignment;
  vector<float> y_alignment;
  vector<float> z_alignment;
  /* alignment parameter of the target layer*/
  double t_align_x;
  double t_align_y;
  double t_align_z;

  vector<float> dec_range;
  vector<float> fit_range;

  vector<int> layer_idx;
  vector<float> layer_z;

  /* event buffer */
  vector<int> trig_id;
  vector<vector<float>> t_position_x;
  vector<vector<int>> t_amp_x;
  vector<vector<int>> t_layer_x;
  vector<vector<float>> t_cluster_x;

  vector<vector<float>> t_position_y;
  vector<vector<int>> t_amp_y;
  vector<vector<int>> t_layer_y;
  vector<vector<float>> t_cluster_y;

  // data_fit temporary buffer
  int layer_select = 0;

  vector<vector<float>> t_position;
  vector<vector<int>> t_amp;
  vector<vector<int>> t_layer;
  vector<vector<float>> t_cluster;

  vector<vector<double>> target_data;
  vector<vector<double>> target_data_amp;
  vector<vector<double>> target_data_cluster;

  vector<int> nr_combinations;
  vector<vector<float>> fec_data_combine;
  vector<vector<float>> fec_data_combine_cluster;

  // result
  struct fit_result_t
  {
    int trigger_id;
    float slope;
    float intercept;
    float rmse;
    float hit_position;
  };
  vector<fit_result_t> fec_data_fit;
  vector<fit_result_t> fec_datax;
  vector<fit_result_t> fec_datay;

  vector<vector<double>> xtarget_data;
  vector<vector<double>> ytarget_data;
  vector<vector<double>> xtarget_data_amp;
  vector<vector<double>> ytarget_data_amp;
  vector<vector<double>> xtarget_data_cluster;
  vector<vector<double>> ytarget_data_cluster;

  // spatial calulate
  vector<vector<float>> tempx;
  vector<vector<float>> tempy;
  string spatial_name;
  double total_stat_x;
  double total_stat_y;

  // draw
  TH1F *spatial;

  // out
  ofstream outall;

  // read detector index
  void idx_gen();
  // read alignment
  void read_dec_file(string filename, vector<float> &dec);
  // read root file
  int read_root_file(string data_infilename);
  // read alignment
  void read_alignment();
  // convert position data
  bool convert_position_data();

  //
  void run();

  void process_data(char axis);

  void clear_data();

  void clear_init();

  // 筛选数据，要求每层探测器都要有hit，如果存在某层没有hit，则舍弃该次缪子事件
  bool data_select();
  // 筛选出每次缪子事件中可能存在的径迹组合
  void data_combine(int level, int layer_idx, vector<int> &count, vector<vector<int>> &containers, vector<vector<float>> &t_channel_2d, vector<float> &temp, vector<float> &temp_current);
  // 挑选出每次缪子事件中最优的径迹，然后反推到待测探测器上
  void data_fit();

  void findTarget(vector<vector<double>> &aimData, vector<vector<double>> &ampData, vector<vector<double>> &clusterData, vector<vector<float>> &fecData, vector<vector<double>> &dataSecondary, vector<vector<double>> &dataAmpSecondary, vector<vector<double>> &dataClusterSecondary, double txOrTy);

  void cal_all_energy(vector<vector<double>> &xampData, vector<vector<double>> &yampData, vector<double> &Ampall);
  void calculateSpatial(vector<vector<double>> &dataSecondary, vector<vector<double>> &dataAmpSecondary, vector<vector<double>> &dataClusterSecondary, vector<vector<double>> &dataTertiary, vector<vector<double>> &dataAmpTertiary, vector<vector<double>> &dataClusterTertiary, const string &filename, bool xory);

  void writeSpatial();

  void draw_spatial(vector<vector<double>> rms, bool xory);
  void draw_energy(vector<vector<double>> energy, bool xory);
  void draw_all_energy(vector<double> energy);
  void draw_cluster(vector<vector<double>> cluster, bool xory);

  void out_result();
};
